package cn.jtfadmin.core.modules.sys.service.impl;

import cn.jtfadmin.base.lang.common.domain.dto.SpecConditionDTO;
import cn.jtfadmin.base.lang.common.domain.dto.SpecPDTO;
import cn.jtfadmin.base.lang.common.service.BaseTreeService;
import cn.jtfadmin.base.lang.common.utils.ExecuterUtils;
import cn.jtfadmin.base.lang.enums.BooleanEnum;
import cn.jtfadmin.core.enums.MenuTypeEnum;
import cn.jtfadmin.core.modules.range.DepartRangeRule;
import cn.jtfadmin.core.modules.range.SysPermissionDataRangeRule;
import cn.jtfadmin.core.modules.sys.domain.dto.UserMenuRDTO;
import cn.jtfadmin.core.modules.sys.domain.entity.SysPermissionEntity;
import cn.jtfadmin.core.modules.sys.domain.entity.SysRoleEntity;
import cn.jtfadmin.core.modules.sys.domain.entity.SysUserEntity;
import cn.jtfadmin.core.modules.sys.service.SysRolePermissionActionService;
import cn.jtfadmin.core.modules.sys.service.SysUserPermissionActionService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户菜单工具
 *
 * @author jtf
 * @since 0.0.2
 */
@Service
@AllArgsConstructor
public class SysUserPermissionActionServiceImpl implements SysUserPermissionActionService {

    private BaseTreeService<SysPermissionEntity> sysPermissionEntityBaseTreeService;

    private SysRolePermissionActionService sysRolePermissionActionService;


    private DepartRangeRule departRangeRule;

    private SysPermissionDataRangeRule sysPermissionDataRangeRule;

    /**
     * 获取用户菜单权限必须在事物范围内，否则会导致
     *
     * @param sysUserEntity 系统用户
     * @return 用户菜单权限，
     */
    @Override
    @Transactional
    public UserMenuRDTO findUserMenu(SysUserEntity sysUserEntity ) {
        // 所有的权限
        List<SysPermissionEntity> permissionEntityList = sysPermissionEntityBaseTreeService.findAll(
                new SpecPDTO<>("sortNo", "asc")
        );

        // 获取用户的菜单权限
        List<SysRoleEntity> roleListTem = sysUserEntity.getRoleList();// 用户所拥有的角色, 临时变量
        List<SysPermissionEntity> userHolderPermissionList = new ArrayList<>();
        Set<String> userHolderPermissionIdSetTem = new HashSet<>(); // 用户拥有的权限id变量，用来去重使用， 临时变量
        if (!CollectionUtils.isEmpty(roleListTem)) {
            for (SysRoleEntity sysRoleEntity : roleListTem) {
                // 如果是超级管理员直接获取所有权限
                if (BooleanEnum.TRUE.equals(sysRoleEntity.getAdminFlag())) {
                    userHolderPermissionList = new ArrayList<>(permissionEntityList);
                    break;
                }
                List<SysPermissionEntity> roleHolderPermissionList = sysRoleEntity.getPermissionList();
                if (!CollectionUtils.isEmpty(roleHolderPermissionList)) {
                    for (SysPermissionEntity sysPermissionEntity : roleHolderPermissionList) {
                        // 去重插入
                        if (userHolderPermissionIdSetTem.add(sysPermissionEntity.getId())) {
                            userHolderPermissionList.add(sysPermissionEntity);
                        }
                    }
                }
            }
        }


        userHolderPermissionIdSetTem = new HashSet<>(); // 用户拥有的权限id变量，用来去重使用， 临时变量
        for (SysPermissionEntity sysPermissionEntity : userHolderPermissionList) {
            userHolderPermissionIdSetTem.add(sysPermissionEntity.getId());
            String parentIds = sysPermissionEntity.getParentIds();
            String[] pidArray = StringUtils.delimitedListToStringArray(parentIds, ",", " ");
            userHolderPermissionIdSetTem.addAll(Arrays.asList(pidArray));
        }
        // 开始构建用户拥有的按钮权限;
        List<UserMenuRDTO.AuthMenuRDTO> authMenuRDTOList = new ArrayList<>();
        List<SysPermissionEntity> menuEntityList = new ArrayList<>();
        for (SysPermissionEntity sysPermissionEntity : permissionEntityList) {
            if (userHolderPermissionIdSetTem.contains(sysPermissionEntity.getId())) {
                if (MenuTypeEnum.MENU.equals(sysPermissionEntity.getMenuType())) {
                    menuEntityList.add(sysPermissionEntity);
                } else if (MenuTypeEnum.PERMISSION.equals(sysPermissionEntity.getMenuType())) {
                    authMenuRDTOList.add(new UserMenuRDTO.AuthMenuRDTO(
                            sysPermissionEntity.getId(),
                            sysPermissionEntity.getPerms(),
                            sysPermissionEntity.getName()
                    ));
                }
            }
        }

        // 构建用户菜单权限
        List<UserMenuRDTO.MenuModelRDTO> menuModelRDTOList = new ArrayList<>();
        List<SysPermissionEntity> topPermissionList = new ArrayList<>();
        for (SysPermissionEntity sysPermissionEntity : menuEntityList) {
            if (!StringUtils.hasText(sysPermissionEntity.getParentId())
                    || !userHolderPermissionIdSetTem.contains(sysPermissionEntity.getParentId())) {
                topPermissionList.add(sysPermissionEntity);
            }
        }

        UserMenuRDTO userMenuRDTO = new UserMenuRDTO();
        for (SysPermissionEntity sysPermissionEntity : topPermissionList) {
            menuModelRDTOList.add(transfer(sysPermissionEntity, menuEntityList));
        }
        userMenuRDTO.setAuth(authMenuRDTOList);
        userMenuRDTO.setMenu(menuModelRDTOList);

        return userMenuRDTO;
    }



    @Override
    public Set<String> findPermissionDataRule(SysUserEntity sysUserEntity) {
        List<SysRoleEntity> roleList = sysUserEntity.getRoleList();
        if (CollectionUtils.isEmpty(roleList)) {
            return Collections.emptySet();
        }
        Set<String> permissionDataRule = new HashSet<>();
        for (SysRoleEntity sysRoleEntity : roleList) {
            BooleanEnum adminFlag = sysRoleEntity.getAdminFlag();
            if (BooleanEnum.TRUE.equals(adminFlag)) {
                permissionDataRule.add(SysPermissionDataRangeRule.all);
                return permissionDataRule;
            } else {
                permissionDataRule.addAll(sysRolePermissionActionService.parseDataRangeKey(sysPermissionDataRangeRule.getName(), sysRoleEntity.getDataRange()));
            }
        }
        return permissionDataRule;
    }

    @Override
    public Set<String> findManagerDepIds(SysUserEntity sysUserEntity) {
        List<SysRoleEntity> roleList = sysUserEntity.getRoleList();
        if (CollectionUtils.isEmpty(roleList)) {
            return Collections.emptySet();
        }
        for (SysRoleEntity sysRoleEntity : roleList) {
            BooleanEnum adminFlag = sysRoleEntity.getAdminFlag();
            if (BooleanEnum.TRUE.equals(adminFlag)) {
                // 超级管理员绕过jpa拦截
                return ExecuterUtils.exec(()->sysPermissionEntityBaseTreeService.findAll((List<SpecConditionDTO>) null)
                                    .stream().map(t->t.getId())
                                    .collect(Collectors.toSet())
                );

            }
        }

        Set<String> dataRangeKeys = new HashSet<>();
        for (SysRoleEntity sysRoleEntity : roleList) {
            dataRangeKeys.addAll(sysRolePermissionActionService.parseDataRangeKey(departRangeRule.getName(), sysRoleEntity.getDataRange()));
        }
        return departRangeRule.parseKeys(dataRangeKeys, sysUserEntity);
    }



    private boolean isWWWHttpUrl(String url) {
        if (url != null && (url.startsWith("http://") || url.startsWith("https://"))) {
            return true;
        }
        return false;
    }

    /**
     * 通过URL生成路由name（去掉URL前缀斜杠，替换内容中的斜杠‘/’为-） 举例： URL = /isystem/role RouteName =
     * isystem-role
     *
     * @return
     */
    private static String urlToRouteName(String url) {
        if (StringUtils.hasText(url)) {
            if (url.startsWith("/")) {
                url = url.substring(1);
            }
            url = url.replace("/", "-");

            // 特殊标记
            url = url.replace(":", "@");
            return url;
        } else {
            return null;
        }
    }

    private UserMenuRDTO.MenuModelRDTO transfer(SysPermissionEntity p, List<SysPermissionEntity> source) {
        String pid = p.getId();
        UserMenuRDTO.MenuModelRDTO menuRDTO = new UserMenuRDTO.MenuModelRDTO();
        menuRDTO.setId(pid);

        menuRDTO.setRouteFlag(p.getRouteFlag());// 表示不生成路由

        if (isWWWHttpUrl(p.getUrl())) {
            menuRDTO.setPath(DigestUtils.md5DigestAsHex(p.getUrl().getBytes(StandardCharsets.UTF_8)));
        } else {
            menuRDTO.setPath(p.getUrl());
        }
        menuRDTO.setName(urlToRouteName(p.getUrl()));
        // 是否隐藏路由，默认都是显示的
        menuRDTO.setHidden(p.getHidden());
        menuRDTO.setRedirect(p.getRedirect());
        menuRDTO.setComponent(p.getComponent());
        List<SysPermissionEntity> permissionChildren = source.stream().filter(t -> pid.equals(t.getParentId()))
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(permissionChildren)) {
            List<UserMenuRDTO.MenuModelRDTO> children = new ArrayList<>();
            for (SysPermissionEntity permissionChild : permissionChildren) {
                children.add(transfer(permissionChild, source));
            }
            if (!CollectionUtils.isEmpty(children)) {
                menuRDTO.setChildren(children);
            }
        }
        UserMenuRDTO.MetaRDTO metaRDTO = new UserMenuRDTO.MetaRDTO();
        metaRDTO.setKeepAlive(BooleanEnum.TRUE.equals(p.getKeepAlive()));// 默认不缓存页面
        metaRDTO.setTitle(p.getName());
        metaRDTO.setIcon(p.getIcon());
        metaRDTO.setUrl(p.getUrl());
        menuRDTO.setMeta(metaRDTO);
        return menuRDTO;
    }

}
